
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Random;
import java.io.OutputStreamWriter;

public class GameAI extends Thread { 

	private static int lastY, lastX;
	private static int GamesizeX, GamesizeY;
	private static PrintWriter out;
	private static int num = 0;
	private BufferedReader in;
	static Boolean Turn = false;
	static Socket socket;
	final int PORT = 2000;
	InetAddress addr;
	private static Boolean predict_once, toGoal = true;

	public GameAI() throws IOException{
		System.out.println("Main constructor!");

		/* Add connection to local server */
		addr = InetAddress.getByName("127.0.0.1"); 
		socket = new Socket(addr, PORT);
		System.out.println("After Socket");

		/* Create in and out */
		this.in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
		GameAI.out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true); 		
	}

	public void run()
	{
		// Get the game plan size
		String size;
		try {
			size = in.readLine();
			String[] size_split = size.split(",");
			System.out.println("AI recived plansize " + size_split[0] + "," + size_split[1]);
			GamesizeX = Integer.parseInt(size_split[0]) + 1;
			GamesizeY = Integer.parseInt(size_split[1]) + 3;

		}
		catch (IOException e) { e.printStackTrace(); }

		// Send the player name
		System.out.println("My playername is set to : AI");
		out.println("AI");
		try {
			System.out.println("Our AI is playing against " + in.readLine());
		} 
		catch (IOException e) { e.printStackTrace(); }

		/* Start the ServerListener for our AI */
		ServerListener SL = new ServerListener(in, false); // Set human to false
		SL.start();
	}

	/** Main function for AI, receive and make function call based on further movements
	 * @param serverData receiving data/command from server by ServerListener
	 * @throws IOException
	 * @throws InterruptedException
	 * @see ServerListener
	 */
	@SuppressWarnings("deprecation") // To SuppressWarning about Thread.currentThread().stop(); (No good one, but can't find any better)
	static void TalkToServer(String serverData) throws IOException, InterruptedException {

		/* draw, does only update lastX&Y for AI*/
		if(serverData.startsWith("draw")){
			String rcv = serverData;
			String split[] = rcv.split(",");

			lastX = Integer.parseInt(split[3]); // Update "last position"
			lastY = Integer.parseInt(split[4]);	
		}

		/* When AI receive highscore it stop the current thread, but server is still running */
		else if(serverData.startsWith("highscore"))
		{
			System.out.println("Quit");
			Thread.currentThread().stop(); // As to it is no working way to close an thread successfully
		}

		/* retValid, does only update lastX&Y for AI (this one is not needed)*/
		else if(serverData.startsWith("retValid"))
		{
			num = 1; // Reset out direction picker
			String rcv = serverData;
			String split[] = rcv.split(",");

			lastX = Integer.parseInt(split[3]); // Update "last position"
			lastY = Integer.parseInt(split[4]);
		}

		/* Here starts the actual movement decider for the AI */
		else if(serverData.startsWith("Status: Player (AI) turn")){ 
			if(lastX == 1){ // If 1 step away from the wall .. do a bounce
				AI_movement(1);
				predict_once = true;
			}
			else if(lastX == GamesizeX-2){ // If 1 step away from the wall .. do a bounce
				AI_movement(2);
				predict_once = true;
			}
			else {
				AI_movement(0);
				predict_once = true;
			}
		}

		/* If AI bounce or land on an already traveled node*/
		else if(serverData.startsWith("Status: Make another")){
			if(lastX == 1){ // If 1 step away from the wall .. do a bounce
				AI_movement(1);
				predict_once = true;
			}
			else if(lastX == GamesizeX-2){ // If 1 step away from the wall .. do a bounce
				AI_movement(2);
				predict_once = true;
			}
			else {
				AI_movement(0);
				predict_once = true;
			}
		}

		/* If AI moves to an position that he can not */
		else if(serverData.startsWith("Status: Invalid move")){
			if(predict_once){
				if(lastX == 1){ // If 1 step away from the wall .. do a bounce
					AI_movement(1);
					predict_once = false;
				}
				else if(lastX == GamesizeX-2){ // If 1 step away from the wall .. do a bounce
					AI_movement(2);
					predict_once = false;
				}
				else if(lastX < (GamesizeX/2)){ // Move closer to the middle
					AI_movement(2);
					predict_once = false;
				}
				else if(lastX > (GamesizeX/2)){ // Move closer to the middle
					AI_movement(1);
					predict_once = false;
				}
				else { // Choose an more random way... (still corrected at AI_movment if it is a stupid move)
					num += 1;
					AI_movement(num);
				}
			}
			else { // Choose an more random way... (still corrected at AI_movment if it is a stupid move)
				num += 1;
				AI_movement(num);
			}
		}

		/* This function too is unnecessary */
		else if(serverData.startsWith("Score")){
			String rcv = serverData;
			String split[] = rcv.split(",");
			if("AI".equals(split[1])){
				System.out.println("Player (AI) score!");
			}
			else {
				System.out.println("Player (" + split[1] + ") score!");
			}
		}
		else
			System.out.println("Unrelevant MSG: " + serverData); // Print out to console the things AI does not need to be concerned about
	}

	/** Here is the actual move called upon, making decision based on where AI is on the board<p>And some corrections when AI
	 * attempt to move outside of the Game, called from TalkToServer()
	 * @param number some early predictions made from previous moves
	 * @see TalkToServer
	 */
	private static void AI_movement(int number)
	{
		number = (number % 7); // This enable us to get a a better move from the start accordingly to position in X-axis

		if(lastX == 0){ // Rules for  (Left border)
			if(num == 0) 
				number = 2;
			else if(num == 4)
				number = 6;
			else {
				number = 2;
			}
		}

		else if(lastX == GamesizeX){ // Rules for  (Right border)
			if(num == 0) 
				number = 1;
			else if(num == 2)
				number = 4;
			else {
				number = 1;
			}
		}

		else if(lastY == 1){ // Rules for  (Top border)
			if(num > 3) 
				number = 0;
			else if(lastX < (GamesizeX/2) - 1) 
				number = 2;
			else
				number = 1;
		}


		else if(lastY == GamesizeY-2){ // Rules for  (Bottom border)
			if((lastX >= (GamesizeX/2)-1 && lastX <= (GamesizeX/2)+1) && toGoal){ 
				System.out.println("Bottom DEBUG 1 " + lastX + " >= " + ((GamesizeX/2)-1) + " && " + lastX + " <= " +  ((GamesizeX/2)+1));
				number = 0;
				toGoal = !toGoal;
			}

			else if(lastX < (GamesizeX/2) - 1 && number <= 4) {
				System.out.println("Bottom DEBUG 2");
				number = 6;	
			}
			else if(lastY > (GamesizeX/2) + 1 && number <= 4){
				System.out.println("Bottom DEBUG 3");
				number = 5;
			}
			else {
				Random rand = new Random(); 
				number = rand.nextInt(7 - 5) + 5;
			}
		}

		// The case direction of movment
		// [5][7][6]
		// [4][ ][3]
		// [1][0][2]

		switch(number){
		case 0:{
			out.println("validate,AI," + lastX + "," + lastY + "," + lastX + "," + (lastY+1) +  "," + (lastX*(400/GamesizeX)+9) +","+ (lastY*(580/GamesizeY)+9) + "," + (lastX*(400/GamesizeX)+9) +","+  ((lastY+1)*(580/GamesizeY)+9));
			break;
		}
		case 1:{
			out.println("validate,AI," + lastX + "," + lastY + "," + (lastX-1) + "," + (lastY+1) +  "," + (lastX*(400/GamesizeX)+9) +","+ (lastY*(580/GamesizeY)+9) + "," + ((lastX-1)*(400/GamesizeX)+9) +","+  ((lastY+1)*(580/GamesizeY)+9));
			break;
		}
		case 2:{
			out.println("validate,AI," + lastX + "," + lastY + "," + (lastX+1) + "," + (lastY+1) +  "," + (lastX*(400/GamesizeX)+9) +","+ (lastY*(580/GamesizeY)+9) + "," + ((lastX+1)*(400/GamesizeX)+9) +","+  ((lastY+1)*(580/GamesizeY)+9));
			break;
		}
		case 3:{
			out.println("validate,AI," + lastX + "," + lastY + "," + (lastX+1) + "," + lastY +  "," + (lastX*(400/GamesizeX)+9) +","+ (lastY*(580/GamesizeY)+9) + "," + ((lastX+1)*(400/GamesizeX)+9) +","+  (lastY*(580/GamesizeY)+9));
			break;
		}
		case 4:{
			out.println("validate,AI," + lastX + "," + lastY + "," + (lastX-1) + "," + lastY +  "," + (lastX*(400/GamesizeX)+9) +","+ (lastY*(580/GamesizeY)+9) + "," + ((lastX-1)*(400/GamesizeX)+9) +","+  (lastY*(580/GamesizeY)+9));
			break;
		}
		case 5:{
			out.println("validate,AI," + lastX + "," + lastY + "," + (lastX-1) + "," + (lastY-1) +  "," + (lastX*(400/GamesizeX)+9) +","+ (lastY*(580/GamesizeY)+9) + "," + ((lastX-1)*(400/GamesizeX)+9) +","+  ((lastY-1)*(580/GamesizeY)+9));
			break;
		}
		case 6:{
			out.println("validate,AI," + lastX + "," + lastY + "," + (lastX+1) + "," + (lastY-1) +  "," + (lastX*(400/GamesizeX)+9) +","+ (lastY*(580/GamesizeY)+9) + "," + ((lastX+1)*(400/GamesizeX)+9) +","+  ((lastY-1)*(580/GamesizeY)+9));
			break;
		}
		case 7:{
			out.println("validate,AI," + lastX + "," + lastY + "," + lastX + "," + (lastY-1) +  "," + (lastX*(400/GamesizeX)+9) +","+ (lastY*(580/GamesizeY)+9) + "," + (lastX*(400/GamesizeX)+9) +","+  ((lastY-1)*(580/GamesizeY)+9));
			break;
		}
		}
	}
}

